/* cvtest.c
 *	Simple program to test the CV-related syscalls
 *	
 *	Does syscalls that create, acquire, release, and destroy locks and create, wait, signal, broadcast, and destory CVs
 */
#include "syscall.h"

void CreateCVTest();
void SignalTest();
void WaitTest();
void BroadcastTest();
void DestroyCVTest();
void ForkTest();

int main(int argc, char **argv)
{
	SignalTest();
	BroadcastTest();
	DestroyCVTest();

	/*
	ForkTest();
	WaitTest(); ->Inside ForkTest()*/
	CreateCVTest();
}

void CreateCVTest()
{
    int cvIndex, lockIndex, i;
    PrintOut("\n\n********************CREATECV TESTS**********************\n\n", 64, ConsoleOutput); 
    
    /*Correct Use - Should Pass*/
    PrintOut("\nTEST 1: Using Create Correctly................................\n", 64, ConsoleOutput); 
    CreateCV(1);
    
    PrintOut("\nTEST 2: Using Create Repeatedly to create different CVs.......\n", 64, ConsoleOutput); 
    for (i = 0; i < 10; i++)
    {
        CreateCV(1); /*Create a lock. An int that indexes the locks location in an array in the kernel will be returned*/
    }

	PrintOut("\nTEST 3: Using Create to make more CVs than the maximum........\n", 64, ConsoleOutput); 
    for (i = 0; i < 400; i++)
    {
        CreateCV(1); /*Create a CV. An int that indexes the CVs location in an array in the kernel will be returned*/
    }
}

void SignalTest()
{
    int lockIndex, lockIndex2, cvIndex, i;
    
    PrintOut("\n\n********************SIGNAL TESTS***********************\n\n", 64, ConsoleOutput); 
    
    /*Correct Use - Should Pass*/
    PrintOut("\nTEST 1: Using Signal on newly created CV......................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/

	PrintOut("\nTEST 2: Using Signal on same CV twice in a row on same lock...\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	Signal(cvIndex, lockIndex);

	PrintOut("\nTEST 3: Using Signal on same CV twice in a row on two different acquired locks\n", 80, ConsoleOutput);
    lockIndex = CreateLock();
	lockIndex2 = CreateLock();
	Acquire(lockIndex);
	Acquire(lockIndex2);
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	Signal(cvIndex, lockIndex2);

	PrintOut("\nTEST 4: Using Signal after Broadcast on same lock.............\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex);
	Signal(cvIndex, lockIndex);

	PrintOut("\nTEST 5: Using Signal after Broadcast on different lock........\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	lockIndex2 = CreateLock();
	Acquire(lockIndex);
	Acquire(lockIndex2);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex2);
	Signal(cvIndex, lockIndex);
    
    /*Incorrect Use - Should Fail and print error message*/
    PrintOut("\nTEST 6: Using Signal on uninitialized lock....................\n", 64, ConsoleOutput);
	cvIndex = CreateCV();
    Signal(cvIndex, 100); /*first int is index of CV, and second int is index of lock*/

	PrintOut("\nTEST 7: Using Signal on uninitialized CV......................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
    Signal(100, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTEST 8: Using Signal on uninitialized lock and uninitialized CV\n", 65, ConsoleOutput);
    Signal(200, 200);

	PrintOut("\nTEST 9: Using Signal on unacquired lock.......................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTEST 10: Using Signal on released lock........................\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	Release(lockIndex);
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTEST 11: Using Signal on destroyed lock.......................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	Release(lockIndex);
	DestroyLock(lockIndex);
	cvIndex = CreateCV();
	Signal(cvIndex, lockIndex);
	
    /*Incorrect Use - Should Fail and print error message from Kernel code.*/
    PrintOut("\nTEST 12: Using Signal on a lock index out of bounds...........\n", 64, ConsoleOutput);
    cvIndex = CreateCV();
    Signal(cvIndex, 500); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTEST 13: Using Signal on a CV index out of bounds.............\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Signal(500, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTEST 14: Using Signal on a lock and CV both index out of bounds.\n", 66, ConsoleOutput);
    Signal(500, 500); /*first int is index of CV, and second int is index of lock*/
	
    PrintOut("\nTEST 15: Using Signal on a negative lock index................\n", 64, ConsoleOutput);
    cvIndex = CreateCV();
    Signal(cvIndex, -2);
	
	PrintOut("\nTEST 16: Using Signal on a negative cv index..................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Signal(-2, lockIndex);
	
	PrintOut("\nTEST 17: Using Signal on a negative lock and cv index.........\n", 64, ConsoleOutput);
    Signal(-2, -2);

	PrintOut("\nTest 18: Using Signal with numeric strings instead of ints....\n", 64);
	Signal("2", "2");

	PrintOut("\nTest 19: Using Signal with character strings instead of ints..\n", 64);
	Signal("hat", "cat");
	
}

void BroadcastTest()
{
	int lockIndex, lockIndex2, cvIndex, i;
    
    PrintOut("\n\n********************BROADCAST TESTS********************\n\n", 64, ConsoleOutput); 
    
    /*Correct Use - Should Pass*/
    PrintOut("Test 1: Using Broadcast on newly created CV....................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTest 2: Using Broadcast on same CV twice in a row on same lock\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	Broadcast(cvIndex, lockIndex);
	
	PrintOut("\nTest 3: Using Broadcast on same CV twice in a row on two different acquired locks\n", 83, ConsoleOutput);
    lockIndex = CreateLock();
	lockIndex2 = CreateLock();
	Acquire(lockIndex);
	Acquire(lockIndex2);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	Broadcast(cvIndex, lockIndex2);

	PrintOut("\nTest 4: Using Broadcast after Signal on same lock.............\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
	Signal(cvIndex, lockIndex);
    Broadcast(cvIndex, lockIndex);
    
	PrintOut("\nTest 5: Using Broadcast after Signal on different lock........\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	lockIndex2 = CreateLock();
	Acquire(lockIndex);
	Acquire(lockIndex2);
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex2);
    Broadcast(cvIndex, lockIndex);
    Write("\n", 2, ConsoleOutput);
    
    /*Incorrect Use - Should Fail and print error message*/
    PrintOut("\nTest 6: Using Broadcast on uninitialized lock.................\n", 64, ConsoleOutput);
	cvIndex = CreateCV();
    Broadcast(cvIndex, 100); /*first int is index of CV, and second int is index of lock*/

	PrintOut("\nTest 7: Using Broadcast on uninitialized CV...................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
    Broadcast(100, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTest 8: Using Broadcast on uninitialized lock and uninitialized CV\n", 68, ConsoleOutput);
    Broadcast(200, 200);
	
	PrintOut("\nTest 9: Using Broadcast on unacquired lock....................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTest 10: Using Broadcast on released lock.....................\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	Release(lockIndex);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTest 11: Using Broadcast on destroyed lock....................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	Release(lockIndex);
	DestroyLock(lockIndex);
	cvIndex = CreateCV();
	Broadcast(cvIndex, lockIndex);
	
    /*Incorrect Use - Should Fail and print debug message from Kernel code. Must run in debug to see (-d) */
    PrintOut("\nTest 12: Using Broadcast on a lock index out of bounds........\n", 64, ConsoleOutput);
    cvIndex = CreateCV();
    Broadcast(cvIndex, 500); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTest 13: Using Broadcast on a CV index out of bounds..........\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Broadcast(500, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	PrintOut("\nTest 14: Using Broadcast on a lock and CV both index out of bounds.\n", 69, ConsoleOutput);
    Broadcast(500, 500); /*first int is index of CV, and second int is index of lock*/
	
    PrintOut("\nTest 15: Using Broadcast on a negative lock index.............\n", 64, ConsoleOutput);
    cvIndex = CreateCV();
    Broadcast(cvIndex, -2);

	PrintOut("\nTest 16: Using Broadcast on a negative cv index...............\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
    Broadcast(-2, lockIndex);
	
	PrintOut("\nTest 17: Using Broadcast on a negative lock and cv index......\n", 64, ConsoleOutput);
    Broadcast(-2, -2);
}

void DestroyCVTest()
{
    int lockIndex, cvIndex, i;
    
    PrintOut("\n\n********************DESTROYCV TESTS*********************\n\n", 64, ConsoleOutput); 
    
    /*Correct Use - Should Pass*/
    PrintOut("Test 1: Using Destroy after a create...........................\n", 64, ConsoleOutput); 
    cvIndex = CreateCV();
    DestroyCV(cvIndex);
    
    PrintOut("\nTest 2: Using Destroy after a Signal..........................\n", 64, ConsoleOutput); 
    lockIndex = CreateLock();
	cvIndex = CreateCV();
    Signal(cvIndex, lockIndex);
    DestroyCV(cvIndex);
    
    /*Incorrect Use - Should Fail and print error message*/
    PrintOut("\nTest 3: Using Destroy on uninitialized CV.....................\n", 64, ConsoleOutput); 
    DestroyCV(50);
    
    PrintOut("\nTest 4: Using Destroy on a destroyed cv.......................\n", 64, ConsoleOutput); 
    cvIndex = CreateCV();
    DestroyCV(cvIndex);
    DestroyCV(cvIndex);
    
    PrintOut("\nTest 5: Using Destroy multiple times in a row on same CV......\n", 64, ConsoleOutput); 
    cvIndex = CreateCV();
    for(i=0; i<5; i++)
    {
        DestroyCV(cvIndex);
    }
    
    PrintOut("\nTest 6: Using Destroy at a CV index out of bounds.............\n", 64, ConsoleOutput);
    DestroyCV(600);
    
	PrintOut("\nTest 7: Using Destroy at a negative CV index..................\n", 64, ConsoleOutput);
    DestroyCV(-2);
}

void ForkTest()
{
	int i, lockIndex, cvIndex;
	/*Tests requiring multiple threads*/

	PrintOut("\nTest: Using Create/Signal/(Wait)..............................\n", 64, ConsoleOutput);  
    cvIndex = CreateCV(1);
	lockIndex = CreateLock(1);
    Signal(cvIndex, lockIndex);
    Wait(cvIndex, lockIndex); 

	/*PrintOut("Test: Using Signal after a Wait on same lock...............\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex);
    Signal(cvIndex, lockIndex);
    */

	/*Trying to signal a CV waiting on a different lock
	Run with -d t to get this DEBUG msg: "Signaler's lock doesn't match.\n"*/

	/*PrintOut("Test: Using Broadcast after a Wait on same lock............\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex);
    Broadcast(cvIndex, lockIndex);
    

	/*Write("Test: Using Broadcast after Wait on different lock...............\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	lockIndex2 = CreateLock();
	Acquire(lockIndex);
	Acquire(lockIndex2);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex2);
    Broadcast(cvIndex, lockIndex);
    Write("\n", 2, ConsoleOutput);*/

	/*PrintOut("Test: Using Destroy after a Wait............................\n", 64, ConsoleOutput); 
    lockIndex = CreateLock();
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex);
    DestroyCV(cvIndex);
	*/
}

void WaitTest()
{
    int lockIndex, lockIndex2, cvIndex;
    
    PrintOut("\n\n**********************WAIT TESTS********************\n\n", 64, ConsoleOutput); 
    /*Probably need to wait for fork/exec before can really test Wait*/
    /*Correct Use - Should Pass*/
    PrintOut("Test: Using Wait on newly created CV.......................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	

	PrintOut("Test: Using Signal on same CV twice in a row on same lock....\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	Wait(cvIndex, lockIndex);
	

	PrintOut("Test: Using Signal on same CV twice in a row on two different acquired locks\n", 77, ConsoleOutput);
    lockIndex = CreateLock();
	lockIndex2 = CreateLock();
	Acquire(lockIndex);
	Acquire(lockIndex2);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	Wait(cvIndex, lockIndex2);
	
    
    PrintOut("Test: Using Wait after a Signal on same lock...............\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
	Signal(cvIndex, lockIndex);
    Wait(cvIndex, lockIndex);
    

	PrintOut("Test: Using Wait after Broadcast on same lock...............\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Broadcast(cvIndex, lockIndex);
	Wait(cvIndex, lockIndex);
    
    
    
    /*Incorrect Use - Should Fail and print error message*/
    PrintOut("Test: Using Signal on uninitialized lock.....................\n", 64, ConsoleOutput);
	cvIndex = CreateCV();
    Wait(cvIndex, 100); /*first int is index of CV, and second int is index of lock*/
	

	PrintOut("Test: Using Wait on uninitialized CV.......................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
    Wait(100, lockIndex); /*first int is index of CV, and second int is index of lock*/
	

	PrintOut("Test: Using Wait on uninitialized lock and uninitialized CV\n", 64, ConsoleOutput);
    Wait(200, 200);
	

	PrintOut("Test: Using Wait on unacquired lock........................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	

	PrintOut("Test: Using Signal on released lock..........................\n", 64, ConsoleOutput);
	lockIndex = CreateLock();
	Acquire(lockIndex);
	Release(lockIndex);
	cvIndex = CreateCV();
    Wait(cvIndex, lockIndex); /*first int is index of CV, and second int is index of lock*/
	

	PrintOut("Test: Using Wait on destroyed lock.........................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	Release(lockIndex);
	DestroyLock(lockIndex);
	cvIndex = CreateCV();
	Wait(cvIndex, lockIndex);
	

    /*Incorrect Use - Should Fail and print debug message from Kernel code. Must run in debug to see (-d) */
    PrintOut("Test: Using Wait on a lock index out of bounds.............\n", 64, ConsoleOutput);
    cvIndex = CreateCV();
    Wait(cvIndex, 500); /*first int is index of CV, and second int is index of lock*/
	

	PrintOut("Test: Using Wait on a CV index out of bounds...............\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Wait(500, lockIndex); /*first int is index of CV, and second int is index of lock*/
	
	
	PrintOut("Test: Using Wait on a lock and CV both index out of bounds.\n", 64, ConsoleOutput);
    Wait(500, 500); /*first int is index of CV, and second int is index of lock*/
	
    
    PrintOut("Test: Using Wait on a negative lock index..................\n", 64, ConsoleOutput);
    cvIndex = CreateCV();
    Wait(cvIndex, -2);
	

	PrintOut("Test: Using Wait on a negative cv index....................\n", 64, ConsoleOutput);
    lockIndex = CreateLock();
	Acquire(lockIndex);
	cvIndex = CreateCV();
    Wait(-2, lockIndex);
	

	PrintOut("Test: Using Wait on a negative lock and cv index...........\n", 64, ConsoleOutput);
    Wait(-2, -2);
	
}